package cn.iocoder.ny.module.mall.service.impl;

import cn.iocoder.yudao.module.system.constant.WeChatAppConstants;
import cn.iocoder.ny.module.mall.controller.admin.login.dto.WxLoginDTO;
import cn.iocoder.ny.module.mall.controller.admin.login.vo.WxRegisterVo;
import cn.iocoder.ny.module.mall.domain.MallConfig;
import cn.iocoder.ny.module.mall.domain.MallUser;
import cn.iocoder.ny.module.mall.service.IMallConfigService;
import cn.iocoder.ny.module.mall.service.IMallLoginService;
import cn.iocoder.yudao.module.system.util.OkHttpUtils;
import cn.iocoder.ny.module.mall.utils.WxMessageUtil;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.saas.dto.StaffBindDto;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.system.SystemUsers;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
import cn.iocoder.yudao.module.system.dal.mysql.system.SystemUsersMapper;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthServiceImpl;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.system.ISystemUserService;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static cn.iocoder.ny.module.mall.enums.SmsEnum.SAAS;

/**
 * @author luchunhong
 * @date 2024/10/18/ 16:42
 * @description:
 */
@Service
public class IMallLoginServiceImpl implements IMallLoginService {

    @Autowired
    private IMallConfigService mallConfigService;

    @Resource
    private ISystemUserService systemUserService;

    @Resource
    private AdminAuthServiceImpl adminAuthService;


    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private AdminUserService userService;

    @Resource
    private IMallUserServiceImpl mallUserService;

    @Resource
    private PermissionService permissionService;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private TenantService tenantService;

    @Resource
    private SystemUsersMapper systemUsersMapper;





    /**
     * 微信授权第三方登录(需要查询老数据库的用户数据)
     * 0.通过小程序所获取到的appid来进行判断该用户登录的是哪个租户 获取到tenantId
     * 1.通过获取到的tenantId来进行判断 该用户是需要登录哪个商店
     * 2.获取到用户的手机号/openId/tenantId 来对system_users数据可以进行判断 查询是否有该用户
     * 3.如果不存在该用户则新增且登录
     * 4.如果存在该用户则直接登录
     * 5.如果是店铺管理员第一次登录该店铺system_users有这个用户的信息 则通过查询手机号+tenantId 来进行修改该用户的openId(后续可能用到该字段
     * @return
     */
    @Override
    @Transactional
    public AuthLoginRespVO wxLogin(WxLoginDTO wxLoginDTO) throws Exception {
        //通过小程序所获取到的appid来进行判断该用户登录的是哪个租户
        MallConfig mallConfig = mallConfigService.lambdaQuery().eq(MallConfig::getAppid, wxLoginDTO.getAppId()).one();
        String wxToken = getWXToken(mallConfig.getAppid(), mallConfig.getSecret());
        //获取微信手机号
        String wxPhone = getWXPhone(wxToken, wxLoginDTO.getPhoneCode());
        String wxOpenId = getWxOpenId(mallConfig.getAppid(), mallConfig.getSecret(), wxLoginDTO.getCode());
        if (mallConfig != null) {
            TenantDO tenant = tenantService.getTenant(mallConfig.getTenantId());
            // 得到该用户所登录的商店id
            Long tenantId = mallConfig.getTenantId();
            // 通过获取到的tenanId以及手机号来进行判断
            SystemUsers users = systemUserService.lambdaQuery().eq(SystemUsers::getMobile, wxPhone)
                    .eq(SystemUsers::getTenantId, tenantId).one();
            // 如果不为空 则登录成功 创建token
            if (users != null) {
                //如果openId为空的话
                MallUser mallUser = mallUserService.lambdaQuery().eq(MallUser::getTenantId, mallConfig.getTenantId())
                        .eq(MallUser::getUserId, users.getId()).one();
                if (mallUser == null){
                    // 保存到商品表内
                    create(mallConfig.getTenantId(),users.getId(), wxLoginDTO.getAppId(),Math.toIntExact(mallConfig.getId()),wxOpenId);
                }

                if (ObjectUtils.isEmpty(users.getOpenId())) {
                    systemUserService.lambdaUpdate().eq(SystemUsers::getMobile, wxPhone).eq(SystemUsers::getTenantId, tenantId)
                            .set(SystemUsers::getOpenId, wxOpenId).update();
                }
                MallUser mallUserS = mallUserService.lambdaQuery().eq(MallUser::getTenantId, mallConfig.getTenantId())
                        .eq(MallUser::getUserId, users.getId()).one();
                if (ObjectUtils.isEmpty(mallUserS.getOpenId())){
                    mallUserService.lambdaUpdate().eq(MallUser::getTenantId, mallConfig.getTenantId()).eq(MallUser::getUserId, users.getId())
                            .set(MallUser::getOpenId, wxOpenId).update();
                }

                AuthLoginRespVO tokenAfterLoginSuccess = adminAuthService.createTokenAfterLoginSuccess(users.getId(), users.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
                tokenAfterLoginSuccess.setTenantId(tenantId);
                tokenAfterLoginSuccess.setTenantName(tenant.getName());
                return tokenAfterLoginSuccess;
            } else if (users == null) {
                // 为空则进行注册 代表没有该用户
                // 进行注册
                // 保存到system_users表内
                SystemUsers systemUsers = new SystemUsers();
                systemUsers.setNickname(wxLoginDTO.getNickName());
                systemUsers.setUsername(wxPhone);
                systemUsers.setMobile(wxPhone);
                systemUsers.setTenantId(tenantId);
                systemUsers.setAvatar(wxLoginDTO.getAvatar());
                systemUsers.setOpenId(wxOpenId);
                boolean save = systemUserService.save(systemUsers);
                if (save) {
                    Long id = systemUsers.getId();
                    // 保存至商品表
                    create(mallConfig.getTenantId(),id, wxLoginDTO.getAppId(),Math.toIntExact(mallConfig.getId()),wxOpenId);
                    StaffBindDto staffBindDto = new StaffBindDto();

                    RoleDO roleDO = roleMapper.selectByCodeOrTenantId("common", tenantId);
                    if (ObjectUtils.isEmpty(roleDO)){
                        throw new Exception("商家配置错误");
                    }
                    staffBindDto.setRoleIds(Collections.singleton(roleDO.getId()));
                    // 这个用户设置为普通用户
                    permissionService.assignUserRole(systemUsers.getId(), staffBindDto.getRoleIds());
                    AuthLoginRespVO tokenAfterLoginSuccess = adminAuthService.createTokenAfterLoginSuccess(id, systemUsers.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
                    tokenAfterLoginSuccess.setTenantId(tenantId);
                    tokenAfterLoginSuccess.setTenantName(tenant.getName());
                    return tokenAfterLoginSuccess;
                }
            }

        }
        return null;
    }

    /**
     *
     * 根据手机号+密码登录
     *
     * @param wxLoginDTO
     * @return
     */

    @Override
    @Transactional
    public AuthLoginRespVO loginNormal(WxLoginDTO wxLoginDTO) throws Exception {
        //通过小程序所获取到的appid来进行判断该用户登录的是哪个租户
        MallConfig mallConfig = mallConfigService.lambdaQuery().eq(MallConfig::getAppid, wxLoginDTO.getAppId()).one();
        String wxOpenId = getWxOpenId(mallConfig.getAppid(), mallConfig.getSecret(), wxLoginDTO.getCode());
        if (!ObjectUtils.isEmpty(mallConfig)) {
            // 通过用户输入的手机号+密码来进行判断是否存在该用户+租户
            SystemUsers users = systemUserService.lambdaQuery().eq(SystemUsers::getUsername, wxLoginDTO.getUserName())
                    .eq(SystemUsers::getTenantId, mallConfig.getTenantId()).one();
            // 账号不存在
            TenantDO tenant = tenantService.getTenant(mallConfig.getTenantId());

            if (users == null) {
                throw new RuntimeException("登录失败,该账号不存在");
            }
            // 验证密码是否存在
            if (!userService.isPasswordMatch(wxLoginDTO.getPassword(),users.getPassword())) {
                throw new RuntimeException("登录失败,账号密码不正确");
            }
            //如果openId为空的话
            MallUser mallUser = mallUserService.lambdaQuery().eq(MallUser::getTenantId, mallConfig.getTenantId())
                    .eq(MallUser::getUserId, users.getId()).one();
            if (mallUser == null){
                // 保存到商城用户表内
                create(mallConfig.getTenantId(),users.getId(), wxLoginDTO.getAppId(),Math.toIntExact(mallConfig.getId()),wxOpenId);

            }
            if (ObjectUtils.isEmpty(users.getOpenId())) {
                systemUserService.lambdaUpdate().eq(SystemUsers::getMobile, wxLoginDTO.getUserName()).eq(SystemUsers::getTenantId, mallConfig.getTenantId())
                        .set(SystemUsers::getOpenId, wxOpenId).update();
            }
            MallUser mallUserS = mallUserService.lambdaQuery().eq(MallUser::getTenantId, mallConfig.getTenantId())
                    .eq(MallUser::getUserId, users.getId()).one();
            if (ObjectUtils.isEmpty(mallUserS.getOpenId())){
                mallUserService.lambdaUpdate().eq(MallUser::getTenantId, mallConfig.getTenantId()).eq(MallUser::getUserId, users.getId())
                        .set(MallUser::getOpenId, wxOpenId).update();
            }

            // 如果已注册 则进行登录
            AuthLoginRespVO tokenAfterLoginSuccess = adminAuthService.createTokenAfterLoginSuccess(users.getId(), users.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
            tokenAfterLoginSuccess.setTenantName(tenant.getName());
            tokenAfterLoginSuccess.setTenantId(mallConfig.getTenantId());
            return tokenAfterLoginSuccess;
        }
        return null;
    }

    /**
     * 注册
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Boolean register(WxRegisterVo wxRegisterVo) throws Exception {
        //通过小程序所获取到的appid来进行判断该用户登录的是哪个租户
        boolean smsBoolean = checkPhoneMessageCode(wxRegisterVo.getMobile(), wxRegisterVo.getMessageCode());
        if (smsBoolean) {
            MallConfig mallConfig = mallConfigService.lambdaQuery().eq(MallConfig::getAppid, wxRegisterVo.getAppId()).one();
        if (!ObjectUtils.isEmpty(mallConfig)) {
            SystemUsers users = systemUserService.lambdaQuery().eq(SystemUsers::getMobile, wxRegisterVo.getMobile())
                    .eq(SystemUsers::getTenantId, mallConfig.getTenantId()).one();
            /**
             * 验证码判断 获取验证码通过手机号
             */
                if (users != null) {
                    // 如果不为空则代表该用户已存在 不需要注册
                    throw new Exception("该用户已存在");
                }
                if (!wxRegisterVo.getPassword().equals(wxRegisterVo.getPasswordAgain())) {
                    throw new Exception("两次密码输入不一致");
                }
                SystemUsers systemUsers = new SystemUsers();
                systemUsers.setAvatar(wxRegisterVo.getAvatar());
                systemUsers.setNickname(wxRegisterVo.getNickName());
                systemUsers.setUsername(wxRegisterVo.getMobile());
                systemUsers.setMobile(wxRegisterVo.getMobile());
                systemUsers.setTenantId(mallConfig.getTenantId());
                systemUsers.setPassword(encodePassword(wxRegisterVo.getPassword()));

                //设置默认头像
                systemUsers.setAvatar("https://cm.cmzg.vip/attachment/images/global/WvzH96C9xkthaFe6RvAFv5s5rrKHXc.png");
                boolean save = systemUserService.save(systemUsers);
            if (save) {
                // 保存到商城用户表
                create(mallConfig.getTenantId(),systemUsers.getId(), wxRegisterVo.getAppId(),Math.toIntExact(mallConfig.getId()),null);
                // 配置权限 默认为普通用户
                StaffBindDto staffBindDto = new StaffBindDto();
                RoleDO roleDO = roleMapper.selectByCodeOrTenantId("common", mallConfig.getTenantId());
                if (ObjectUtils.isEmpty(roleDO)){
                    throw new Exception("商家配置错误");
                }
                staffBindDto.setRoleIds(Collections.singleton(roleDO.getId()));
                // 这个用户设置为普通用户
                permissionService.assignUserRole(systemUsers.getId(), staffBindDto.getRoleIds());
                // 配置权限 默认为普通用户
//                UserRoleDO userRoleDO = new UserRoleDO();
//                userRoleDO.setUserId(systemUsers.getId());
//                userRoleDO.setTenantId(mallConfig.getTenantId());
//                userRoleDO.setRoleId(1L);
//                userRoleMapper.insert(userRoleDO);
                redisTemplate.delete(wxRegisterVo.getMobile());
                return true;
                }
                return false;
            }
            throw new Exception("商家配置错误,请联系管理员");
        }
        throw new Exception("验证码有误,请重新输入");
    }

    /**
     * 找回密码
     *
     * @param
     * @return
     */
    @Override
    public Boolean forget(WxRegisterVo wxRegisterVo) throws Exception {
        /**
         * 验证码判断
         */
        boolean smsBoolean = checkPhoneMessageCode(wxRegisterVo.getMobile(), wxRegisterVo.getMessageCode());
        if (smsBoolean) {
                MallConfig mallConfig = mallConfigService.lambdaQuery().eq(MallConfig::getAppid, wxRegisterVo.getAppId()).one();
                if (!ObjectUtils.isEmpty(mallConfig)){
                SystemUsers users = systemUserService.lambdaQuery().eq(SystemUsers::getMobile, wxRegisterVo.getMobile())
                        .eq(SystemUsers::getTenantId, mallConfig.getTenantId()).one();
                if (users == null) {
                    throw new Exception("该用户不存在");
                }
                if (!wxRegisterVo.getPassword().equals(wxRegisterVo.getPasswordAgain())) {
                    throw new Exception("两次密码输入不一致");
                }
                // 修改密码
                Long id = users.getId();
//                systemUserService.lambdaUpdate().eq(SystemUsers::getUsername, users.getUsername()).set(SystemUsers::getPassword, encodePassword(wxRegisterVo.getPassword())).update();
                systemUserService.lambdaUpdate().eq(SystemUsers::getId, id).set(SystemUsers::getPassword, encodePassword(wxRegisterVo.getPassword())).update();
                 // 删除
                redisTemplate.delete(SAAS+wxRegisterVo.getMobile());
                return true;
            }
            throw new Exception("商家配置错误,请联系管理员");
        }
        throw new Exception("验证码输入有误,请仔细检查");
    }

    @Override
    public String responseMsg(HttpServletRequest req) {
        try {
            Map<String, String> xmlMessage = WxMessageUtil.xmlToMap(req); // 将微信返回的 XML 转成 Map
            String msgType = xmlMessage.get("MsgType"); // 消息类型(event 或者 text)
            String fromUserName = xmlMessage.get("FromUserName"); // 用户公众号的OpenID
            List<SystemUsers> list = systemUserService.lambdaQuery().eq(SystemUsers::getOfficialOpenId, fromUserName).list();
            String content;
            String sceneStr = xmlMessage.get("EventKey"); // 从 EventKey 中获取 scene_str
            if (!ObjectUtils.isEmpty(sceneStr) && !ObjectUtils.isEmpty(list)){
                SystemUsers systemUsers = systemUserService.lambdaQuery()
                        .eq(SystemUsers::getOfficialOpenId, fromUserName)
                        .eq(SystemUsers::getStatus, "0")
                        .eq(SystemUsers::getDeleted, "0")
                        .last("LIMIT 1")
                        .one();
                if (!ObjectUtils.isEmpty(systemUsers)){
                    SystemUsers s2 = systemUsersMapper.getTenantIdByUserName(systemUsers.getUsername());
                    // 若是查询不到用户
                    if (ObjectUtils.isEmpty(s2)){
                        return WxMessageUtil.getWxReturnMsg(xmlMessage, "您当前无权限登录");
                    }
                    // 存储到redis内
                    storeUserInfoInRedis(sceneStr, systemUsers, s2);
                    content = "登录成功";
                    return WxMessageUtil.getWxReturnMsg(xmlMessage, content);
                }
            }
            if ("event".equals(msgType)) { // 如果是事件推送
                String eventType = xmlMessage.get("Event"); // 事件类型
                if ("subscribe".equals(eventType)) { // 如果是关注公众号事件
                    return handleSubscribeEvent(xmlMessage,list,sceneStr,fromUserName);
                }
            } else if ("text".equals(msgType)) { // 如果是文本消息
                return handleTextMessage(xmlMessage, list, fromUserName, sceneStr);
            }

            // 如果不是事件也不是文本消息，并且用户未绑定手机号
            if (ObjectUtils.isEmpty(list)) {
                content = "您好，您未绑定手机号，请输入手机号以进行绑定。";
                return WxMessageUtil.getWxReturnMsg(xmlMessage, content);
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return "success";
    }

    @Override
    public Long getTeantIdByAppid(String appId) {
        MallConfig mallConfig = mallConfigService.lambdaQuery().eq(MallConfig::getAppid, appId).one();
        return mallConfig.getTenantId();
    }

    @Override
    public Long wxQrcodeGetTenantId(String sceneStr) {
        Object tenantIdObj = redisTemplate.opsForHash().get(sceneStr, "tenantId");
        if (tenantIdObj == null) {
            return null;
        }
            return Long.valueOf(tenantIdObj.toString());
        }

    @Override
    public AuthLoginRespVO wxGzhLogin(String sceneStr) throws Exception {
        // 从 Redis 中获取必要的对象
        Object tenantIdObj = redisTemplate.opsForHash().get(sceneStr, "tenantId");
        Object mobileObj = redisTemplate.opsForHash().get(sceneStr, "mobile");
        Object userIdObj = redisTemplate.opsForHash().get(sceneStr, "userId");
        Object tenantNameObj = redisTemplate.opsForHash().get(sceneStr, "tenantName");
        if (tenantIdObj == null || mobileObj == null || userIdObj == null || tenantNameObj == null) {
            throw new Exception("登录信息不完整，请检查输入信息。");
        }
        // 创建登录成功后的 token
        AuthLoginRespVO tokenAfterLoginSuccess = adminAuthService.createTokenAfterLoginSuccess(
                Long.valueOf(userIdObj.toString()),
                String.valueOf(mobileObj),
                LoginLogTypeEnum.LOGIN_SOCIAL
        );
        // 设置租户信息
        tokenAfterLoginSuccess.setTenantName(tenantNameObj.toString());
        tokenAfterLoginSuccess.setTenantId(Long.valueOf(tenantIdObj.toString()));
        // 删除
        redisTemplate.delete(sceneStr);
        return tokenAfterLoginSuccess;
    }


    private String handleSubscribeEvent(Map<String, String> xmlMessage, List<SystemUsers> list, String sceneStr, String fromUserName) {
        String content;

        // 如果用户列表为空，说明是新用户，发送欢迎消息
        if (ObjectUtils.isEmpty(list)) {
            content = "你好！欢迎关注本公众号。请输入手机号以进行绑定。";
            return WxMessageUtil.getWxReturnMsg(xmlMessage, content); // 返回消息
        }
        // 查询当前用户的详细信息
        SystemUsers systemUsers = systemUserService.lambdaQuery()
                .eq(SystemUsers::getOfficialOpenId, fromUserName)
                .eq(SystemUsers::getStatus, "0")
                .eq(SystemUsers::getDeleted, "0")
                .last("LIMIT 1")
                .one();
        // 获取与用户相关的租户信息
        SystemUsers tenantInfo = systemUsersMapper.getTenantIdByUserName(systemUsers.getUsername());

        // 如果没有找到租户信息，返回无权限消息
        if (ObjectUtils.isEmpty(tenantInfo)) {
            return WxMessageUtil.getWxReturnMsg(xmlMessage, "您当前无权限登录");
        }
        storeUserInfoInRedis(sceneStr, systemUsers, tenantInfo);
        content = "登录成功";
        return WxMessageUtil.getWxReturnMsg(xmlMessage, content);
    }

    // 将用户信息存储到 Redis 的辅助方法
    private void storeUserInfoInRedis(String sceneStr, SystemUsers systemUsers, SystemUsers tenantInfo) {
        redisTemplate.opsForHash().put(sceneStr, "mobile", systemUsers.getMobile());
        redisTemplate.opsForHash().put(sceneStr, "tenantId", tenantInfo.getTenantId());
        redisTemplate.opsForHash().put(sceneStr, "userId", tenantInfo.getId());
        redisTemplate.opsForHash().put(sceneStr, "tenantName", tenantInfo.getTenantName());
        redisTemplate.expire(sceneStr, 5, TimeUnit.MINUTES); // 设置过期时间
    }


    private String handleTextMessage(Map<String, String> xmlMessage, List<SystemUsers> list, String fromUserName,String sceneStr) {
        String content = xmlMessage.get("Content"); // 获取用户发送的内容

        if (ObjectUtils.isEmpty(list)) { // 检查用户是否已绑定手机号
            if ("绑定手机号".equals(content)) { // 检查用户是否发送了“绑定手机号”
                return WxMessageUtil.getWxReturnMsg(xmlMessage, "请发送您的手机号进行绑定。");
            } else if (content.matches("^1[3-9]\\d{9}$")) { // 如果用户发送的是有效手机号
                boolean isUpdated = systemUserService.lambdaUpdate()
                        .eq(SystemUsers::getMobile, content)
                        .set(SystemUsers::getOfficialOpenId, fromUserName)
                        .update();
                content = isUpdated ? "绑定成功,已成功登录" : "绑定失败,请重新绑定";

                SystemUsers systemUsers = systemUserService.lambdaQuery()
                        .eq(SystemUsers::getOfficialOpenId, fromUserName)
                        .eq(SystemUsers::getStatus, "0")
                        .eq(SystemUsers::getDeleted, "0")
                        .last("LIMIT 1")
                        .one();
                redisTemplate.opsForValue().set(sceneStr,systemUsers.getMobile(),5, TimeUnit.MINUTES);
                return WxMessageUtil.getWxReturnMsg(xmlMessage, content);
            } else {
                content = "您好您当前未完成绑定,请发送有效的手机号,以进行绑定。";
                return WxMessageUtil.getWxReturnMsg(xmlMessage, content);
            }
        }

        if (!ObjectUtils.isEmpty(list) && "绑定手机号".equals(content) || content.matches("^1[3-9]\\d{9}$")) {
            content = "您当前已绑定过手机号,无需再次绑定";
            return WxMessageUtil.getWxReturnMsg(xmlMessage, content);
        }

        return WxMessageUtil.getWxReturnMsg(xmlMessage, "发送的信息未知");
    }






    private String getWxOpenId(String appid,String secret,String code) throws Exception {
        //微信登录方法,请求接口https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
        String message = OkHttpUtils.builder().url(WeChatAppConstants.LOGINURL)
                // 有参数的话添加参数，可多个
                .addParam("appid", appid)
                .addParam("secret", secret)
                .addParam("js_code", code)
                .addParam("grant_type", "authorization_code")
                //.addHeader("Content-Type", "application/json; charset=utf-8")
                .get()
                // 可选择是同步请求还是异步请求
                .async();
        // .sync();
        //message转map
        Map<String, Object> map = JSON.parseObject(message, Map.class);
        String openid = String.valueOf(map.get("openid"));
        if (null==openid){
            throw  new Exception("小程序登录失败，请联系管理员");
        }
        return openid;
    }

    /**
     * 获取微信手机号需要的token
     */
    @SneakyThrows
    private String getWXToken(String appid,String secret){
        String message = OkHttpUtils.builder().url(WeChatAppConstants.PHONETOKENURL)
                // 有参数的话添加参数，可多个
                .addParam("grant_type", "client_credential")
                .addParam("secret", secret)
                .addParam("appid", appid)
                //.addHeader("Content-Type", "application/json; charset=utf-8")
                .get()
                // 可选择是同步请求还是异步请求
                .async();
        Map<String, Object> map = JSON.parseObject(message, Map.class);
        String access_token = String.valueOf(map.get("access_token"));
        if (null==access_token){
            throw  new Exception("小程序登录失败，请联系管理员");
        }
        return access_token;

    }

    /**
     * 获取微信手机号
     * code  调用微信组件获取的零时授权码
     */
    private String getWXPhone(String access_token,String code) throws Exception {
        String message = OkHttpUtils.builder().url(WeChatAppConstants.GETPHONEURL+"?access_token="+access_token)
                // 有参数的话添加参数，可多个
                .addParam("code", code)
//                .addHeader("Content-Type", "application/json; charset=utf-8")
                .post(true)
                // 可选择是同步请求还是异步请求
                .async();
        Map<String, Object> map = JSON.parseObject(message, Map.class);
        Map<String, Object> phoneInfo = (Map<String, Object>) map.get("phone_info");
        String phoneNumber = (String) phoneInfo.get("phoneNumber");
        if (null==phoneNumber){
            throw  new Exception("小程序登录失败，请联系管理员");
        }
        return phoneNumber;

    }

    /**
     * 对密码进行加密
     *
     * @param password 密码
     * @return 加密后的密码
     */
    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    /**
     * 验证码判断
     * @param mobile
     * @param messageCode
     * @return
     */
    public boolean checkPhoneMessageCode(String mobile, String messageCode) {
        // 检查手机号和验证码是否为空
        if (ObjectUtils.isEmpty(mobile) || ObjectUtils.isEmpty(messageCode)) {
            return false; // 任一为空，返回 false
        }
        // 从 reids 获取验证码
        Object code = redisTemplate.opsForValue().get(SAAS+mobile);
        // 验证是否匹配
        return ObjectUtils.isNotEmpty(code) && code.equals(messageCode);
    }

    /**
     * 保存至商城用户表内
     * @param tenantId
     * @param userId
     * @param appId
     * @param mallId
     */
    private void create(Long tenantId, Long userId, String appId, Integer mallId,String openId) {
        MallUser mallUser = new MallUser();
        mallUser.setTenantId(tenantId);
        mallUser.setUserId(userId);
        mallUser.setAppId(appId);
        mallUser.setMallId(mallId);
        if (!ObjectUtils.isEmpty(openId)) {
            mallUser.setOpenId(openId);
        }
        mallUserService.save(mallUser);
    }

}
